package cn.texous.easytalk.manager.service.impl;

import cn.texous.easytalk.commonutil.constant.UserConst;
import cn.texous.easytalk.commonutil.util.ConverterUtils;
import cn.texous.easytalk.manager.config.ServerConfig;
import cn.texous.easytalk.manager.config.mysql.AbstractService;
import cn.texous.easytalk.manager.dao.EtUserFriendMapper;
import cn.texous.easytalk.manager.dao.EtUserGroupMapper;
import cn.texous.easytalk.manager.dao.EtUserMapper;
import cn.texous.easytalk.manager.model.dto.FindUserDto;
import cn.texous.easytalk.manager.model.dto.UserChatGroupDto;
import cn.texous.easytalk.manager.model.dto.UserDto;
import cn.texous.easytalk.manager.model.dto.UserLoginDto;
import cn.texous.easytalk.manager.model.entity.EtUser;
import cn.texous.easytalk.manager.model.entity.EtUserFriend;
import cn.texous.easytalk.manager.model.entity.EtUserGroup;
import cn.texous.easytalk.manager.model.params.friend.AddFriendParam;
import cn.texous.easytalk.manager.model.params.friend.AgreeFriendAddParam;
import cn.texous.easytalk.manager.model.params.friend.DeleteFriendParam;
import cn.texous.easytalk.manager.model.params.friend.FindFriendByIdParam;
import cn.texous.easytalk.manager.model.params.friend.FindFriendByNameParam;
import cn.texous.easytalk.manager.model.params.friend.FriendGroupChangeParam;
import cn.texous.easytalk.manager.model.params.friend.FriendRemarkChangeParam;
import cn.texous.easytalk.manager.model.params.user.UserLoginParam;
import cn.texous.easytalk.manager.model.params.user.UserRegisterParam;
import cn.texous.easytalk.manager.model.vo.UserChatGroupVO;
import cn.texous.easytalk.manager.publisher.EtPublisher;
import cn.texous.easytalk.manager.publisher.RedisPublisher;
import cn.texous.easytalk.manager.publisher.subscribe.EtUserLoginSubscribe;
import cn.texous.easytalk.manager.publisher.subscribe.EtUserLogoutSubscribe;
import cn.texous.easytalk.manager.service.api.EtUserService;
import cn.texous.easytalk.manager.util.SnowFlakeClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;

/**
 * insert description here.
 *
 * @author Showa.L
 * @since 2019-09-02 10:55:33
 */
@Service
public class EtUserServiceImpl extends AbstractService<EtUser> implements EtUserService {

    @Resource
    private EtUserMapper etUserMapper;
    @Resource
    private EtUserGroupMapper etUserGroupMapper;
    @Resource
    private EtUserFriendMapper etUserFriendMapper;
    @Autowired
    private ServerConfig serverConfig;
    @Autowired
    private PasswordEncoder bCryptPasswordEncoder;
    @Autowired
    private EtPublisher etPublisher;

    @Override
    public Boolean hasUser(String code) {
        return etUserMapper.selectByCode(code, UserConst.Status.NORMAL.ordinal()) > 0;
    }

    @Override
    public Boolean existsUsername(String username) {
        int count = etUserMapper.existsUsername(username);
        return count > 0;
    }

    @Override
    @Transactional
    public Boolean register(UserRegisterParam param) {
        EtUser etUser = ConverterUtils.convert(EtUser.class, param);
        if (etUser.getAvatar() == null)
            etUser.setAvatar(serverConfig.getDefaultHeader());
        if (etUser.getSign() == null)
            etUser.setSign(serverConfig.getDefaultSign());
        String code = SnowFlakeClient.userCode();
        etUser.setCode(code);
        etUser.setPassword(bCryptPasswordEncoder.encode(etUser.getPassword()));
        // 注册
        etUserMapper.insertSelective(etUser);
        // 初始化用户默认分组
        initDefaultUserGroup(etUser);
        return true;
    }

    @Override
    public UserLoginDto login(UserLoginParam param) {
        EtUser etUser = etUserMapper.selectByUsername(
                param.getUsername(), UserConst.Status.NORMAL.ordinal());
        if (etUser != null
                && etUser.getPassword()
                .equals(bCryptPasswordEncoder.encode(param.getPassword()))) {
            String token = UUID.randomUUID().toString().replaceAll("-", "");
            UserDto userDto = ConverterUtils.convert(UserDto.class, etUser);
            List<UserChatGroupVO> userChatGroupVos = etUserMapper
                    .selectUserChatGroup(userDto.getCode(), UserConst.Status.NORMAL.ordinal());
            List<UserChatGroupDto> groupDtos = ConverterUtils
                    .convert(UserChatGroupDto.class, userChatGroupVos);
            UserLoginDto userLoginDto = new UserLoginDto(token, userDto, groupDtos);
            etPublisher.publisher(userLoginDto, EtUserLoginSubscribe.TOPIC);
            return userLoginDto;
        }
        return null;
    }

    @Override
    public boolean logout(String token, UserDto userDto) {
        UserLoginDto userLoginDto = new UserLoginDto(token, userDto, null);
        etPublisher.publisher(userLoginDto, EtUserLogoutSubscribe.TOPIC);
        return true;
    }

    @Override
    @Transactional
    public boolean addFriend(AddFriendParam param, UserDto userDto) {
        if (etUserFriendMapper.existsFriend(
                param.getCode(), userDto.getCode(), null) > 0) {
            etUserFriendMapper.updateStatus(param.getCode(),
                    userDto.getCode(), UserConst.Status.WAIT.ordinal());
        } else {
            EtUserFriend etUserFriend = new EtUserFriend();
            etUserFriend.setCreatedBy(userDto.getCode());
            etUserFriend.setRemarkName(param.getRemarkName());
            // 添加用户为待确认状态， 用户同意后才会转为正常状态
            etUserFriend.setStatus(UserConst.Status.WAIT.ordinal());
            etUserFriend.setUserCode(userDto.getCode());
            etUserFriend.setUserGroupCode(param.getUserGroupCode());
            etUserFriend.setFriendCode(param.getCode());
            etUserFriendMapper.insertSelective(etUserFriend);
        }
        // 发布 添加好友请求
        RedisPublisher.addFriend(userDto.getCode(), param.getCode(), userDto.getUsername());
        return true;
    }

    @Override
    public boolean agreeFriendAdd(AgreeFriendAddParam param, UserDto userDto) {
        if (etUserFriendMapper.existsFriend(
                param.getCode(), userDto.getCode(), null) > 0) {
            etUserFriendMapper.updateStatus(param.getCode(),
                    userDto.getCode(), UserConst.Status.NORMAL.ordinal());
        } else {
            EtUserFriend etUserFriend = new EtUserFriend();
            etUserFriend.setCreatedBy(userDto.getCode());
            etUserFriend.setRemarkName(param.getRemarkName());
            // 同意直接设为 正常 状态
            etUserFriend.setStatus(UserConst.Status.NORMAL.ordinal());
            etUserFriend.setUserCode(userDto.getCode());
            etUserFriend.setUserGroupCode(param.getUserGroupCode());
            etUserFriend.setFriendCode(param.getCode());
            etUserFriendMapper.insertSelective(etUserFriend);
        }
        // 更新发起人的好友关联状态
        etUserFriendMapper.updateStatus(userDto.getCode(),
                param.getCode(), UserConst.Status.NORMAL.ordinal());
        // 发布 同意好友添加
        RedisPublisher.addFriend(userDto.getCode(),
                param.getCode(), userDto.getUsername());
        return true;
    }

    @Override
    public boolean deleteFriends(DeleteFriendParam param, UserDto userDto) {
        if (param.getCodes().size() == 1)
            etUserFriendMapper.updateStatus(param.getCodes().get(0),
                    userDto.getCode(), UserConst.Status.DELETE.ordinal());
        else
            etUserFriendMapper.updateStatusBatch(param.getCodes(),
                    userDto.getCode(), UserConst.Status.DELETE.ordinal());
        RedisPublisher.deleteFriends(userDto.getCode(),
                param.getCodes(), userDto.getUsername());
        return true;
    }

    @Override
    public FindUserDto findUserById(FindFriendByIdParam param) {
        EtUser user = etUserMapper.selectByPrimaryKey(param.getId());
        return ConverterUtils.convert(FindUserDto.class, user);
    }

    @Override
    public FindUserDto findUserByName(FindFriendByNameParam param) {
        EtUser user = etUserMapper.selectByUsername(
                param.getUsername(), UserConst.Status.NORMAL.ordinal());
        return ConverterUtils.convert(FindUserDto.class, user);
    }

    @Override
    public boolean changeFriendGroup(FriendGroupChangeParam param, UserDto userDto) {
        int update = etUserFriendMapper.updateUserGroup(
                param.getUserGroupCode(), param.getCode(), userDto.getCode());
        return update > 0;
    }

    @Override
    public boolean changeFriendRemark(FriendRemarkChangeParam param, UserDto userDto) {
        int update = etUserFriendMapper.updateUserRemark(
                param.getRemarkName(), param.getCode(), userDto.getCode());
        return update > 0;
    }

    private void initDefaultUserGroup(EtUser etUser) {
        EtUserGroup etUserGroup = new EtUserGroup();
        etUserGroup.setName(serverConfig.getDefaultUserGroupName());
        etUserGroup.setUserCode(etUser.getCode());
        etUserGroup.setCode(SnowFlakeClient.userGroupCode());
        etUserGroupMapper.insertSelective(etUserGroup);
    }
}
